
#pragma once

#include <QDebug>
#include <QList>
#include <QMap>
#include <QMouseEvent>
#include <QPoint>
#include <QVector2D>
#include <QVector>
#include <QWheelEvent>
#include <QtMath>
#include <cmath>
#include <map>
#include <vector>

namespace qbe::axis {

struct Point {
  double x, y;
  Point() : x(0), y(0){};
  Point(double x, double y) : x(x), y(y){};
  double distance(Point t) { return sqrt(pow(x - t.x, 2) + pow(y - t.y, 2)); };
};

struct BBox {
  double x_min, y_min, x_max, y_max;
  BBox(){};
  BBox(double x_min, double y_min, double x_max, double y_max) : x_min(x_min), y_min(y_min), x_max(x_max), y_max(y_max){};

  double width() { return x_max - x_min; };
  double height() { return y_max - y_min; };
  double center_x() { return x_min + width() / 2; };
  double center_y() { return y_min + height() / 2; };
};

struct AxisGrid {
  std::vector<std::vector<Point>> lines{};
  bool show{true};                            // 是否显示
  double precision{0.001};                    // 精度
  double graph_precision{0.001};              // 画布网格精度
  double pixel_width{50};                     // 像素宽度
  double real_width{0.001};                   // 真实宽度, um
  std::map<double, double> real_width_map{};  // 自动变换真实宽度map
  int num_max{50};                            // 网格线最大数量
  int num_min{10};
  int line_num{10};
  int x_left{0};
  int x_right{10};
  int y_left{0};
  int y_right{10};

  AxisGrid() {
    real_width_map = {};
    real_width_map[0.025] = 0.001;
    real_width_map[0.05] = 0.002;
    real_width_map[0.1] = 0.005;
    real_width_map[0.2] = 0.01;
    real_width_map[0.5] = 0.02;
    real_width_map[1] = 0.05;
    real_width_map[2] = 0.1;
    real_width_map[5] = 0.2;
    real_width_map[10] = 0.5;
    real_width_map[20] = 1;
    real_width_map[50] = 2;
    real_width_map[100] = 5;
    real_width_map[200] = 10;
    real_width_map[500] = 20;
    real_width_map[1000] = 50;
    real_width_map[2000] = 100;
    real_width_map[5000] = 200;
    real_width_map[10000] = 500;
    real_width_map[20000] = 1000;
    real_width_map[50000] = 2000;
    real_width_map[100000] = 5000;
    real_width_map[200000] = 10000;
    real_width_map[500000] = 20000;
    real_width_map[1000000] = 50000;
  };
};

struct AxisRuler {
  double width;
  double height;
  double w;
  int num_max;
  int num_min;
  QList<QVector<double>> paths;
  QList<QVector<double>> texts;

  AxisRuler() : width(20), height(20), w(10), num_max(50), num_min(30){};
  AxisRuler(double width, double height) : width(width), height(height), w(10), num_max(50), num_min(30){};
};

struct AxisMatrix {
  double tran_x, tran_y, scale_x, scale_y;
  AxisMatrix(){};
  AxisMatrix(double scale_x, double scale_y, double tran_x, double tran_y) : scale_x(scale_x), scale_y(scale_y), tran_x(tran_x), tran_y(tran_y){};
  void setTranslate(double tran_x, double tran_y) {
    tran_x = tran_x;
    tran_y = tran_y;
  };
  void setScale(double scale_x, double scale_y) {
    scale_x = scale_x;
    scale_y = scale_y;
  };
};

class Axis {
 public:
  typedef std::shared_ptr<Axis> s_ptr;
  static s_ptr create() { return std::make_shared<Axis>(); }

  Axis();
  ~Axis();

  void init(int width_, int height_, double unit_, double precision_);

  void setCenter();
  Point getGridAdsorpPoint(double x, double y);
  Point getDiagonalAdsorpPoint(Point& startPoint, Point& endPoint);
  void getGridLine();
  void getRulerX();
  void getRulerY();
  void getSplitsAABB();
  void setViewBox(double x, double y, double w, double h);
  void backZero();
  // void drag(double dx, double dy);

  QVector2D getMousePixelXY() { return QVector2D(mouse_pixel_x, mouse_pixel_y); };
  QVector2D getZeroPixelXY() { return QVector2D(zero_pixel_x, zero_pixel_y); };
  QVector2D getPosXY() { return QVector2D(pos_x, pos_y); };
  QVector2D getPosRealXY() { return QVector2D(pos_real_x, pos_real_y); };
  QVector2D getRealXY() { return QVector2D(real_x, real_y); };
  QVector2D getTranXY() { return QVector2D(dx, dy); };
  void updateValue();
  // void onMouseMove(QMouseEvent *e);
  void tranlate(float _dx, float _dy);
  void onMouseMove(float x, float y);
  void onMouseWheel(QWheelEvent* e);
  void onMouseWheel(int delta);
  std::vector<double> getScreenBox();
  void adaptBox(double min_x, double min_y, double max_x, double max_y);

  void resize(int width_, int height_) {
    width = width_;
    height = height_;
    dx = width / 2.0;
    dy = height / 2.0;
    updateValue();
  };

  void setWidth(int width_) { width = width_; };
  void setHeight(int height_) { height = height_; };
  void setUnit(double unit_) { unit = unit_; };
  void setPrecision(double precision_) { precision = precision_; };
  void setTaskGrid(int row, int col) {
    splits_row = row;
    splits_col = col;
    splits_num = row * col;
  };

  // 将坐标系从真实坐标系转换到像素坐标系
  Point real2pixel(double rx, double ry) {
    double factor = 1000.0 / scale / unit_scale;

    auto t_pos_real_x = rx / factor;
    auto t_pos_real_y = ry / factor;

    auto t_pos_x = t_pos_real_x + dx;
    auto t_pos_y = -t_pos_real_y + dy;

    auto t_gl_mouse_px = -width / 2.0 + t_pos_x;
    auto t_gl_mouse_py = -(-height / 2.0 + t_pos_y);

    return Point{t_gl_mouse_px, t_gl_mouse_py};
  };

  // private:
  int width;
  int height;
  double unit;
  double precision;

  double dx, dy;
  double gl_dx, gl_dy;
  double gl_zero_px, gl_zero_py;
  double gl_mouse_px, gl_mouse_py;
  double gl_real_px, gl_real_py;
  double gl_adsorp_px, gl_adsorp_py;

  double real_x, real_y;
  double pos_x, pos_y;
  double pos_real_x, pos_real_y;
  double mouse_real_x, mouse_real_y;
  double mouse_pixel_x, mouse_pixel_y;
  double zero_pixel_x, zero_pixel_y;
  double draw_x, draw_y;
  double board_real_x, board_real_y;

  double unit_scale;
  double cell_scale;
  double scale, scale_max, scale_min;
  double line_width;

  AxisMatrix matrix;

  Point mouse_point;

  // bool adsorp_diagonal{false};
  bool adsorp{true};
  Point adsorp_point;
  Point adsorp_real_point;
  Point adsorp_pixel_point;
  double adsorp_precision{1};

  AxisGrid grid;
  AxisRuler rulerX;
  AxisRuler rulerY;

  BBox bounds;
  BBox bounds_box;
  BBox bounds_unit;
  BBox bounds_mouse;
  double bounds_mouse_range{5};

  // 多线程分割参数
  int splits_num{4};
  int splits_row{2};
  int splits_col{2};
  std::vector<BBox> bounds_box_splits;

  double grid_scale = 4;

  // bool middle_press{false};
};

}  // namespace qbe::axis
